<script setup lang="ts">
import { useMonacoEditor } from '@/hooks/web/useMonacoEditor'
import { onMounted, computed, watch, ref } from 'vue'
import { ElSelect, ElOption, ElFormItem, ElForm } from 'element-plus'
import { languageOptions, themeOptions } from './config'
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc';
import { MonacoLanguageClient} from "monaco-languageclient";
import {CloseAction,ErrorAction, MessageTransports} from "vscode-languageclient/browser";
const props = withDefaults(
  defineProps<{
    width?: string | number
    height?: string | number
    languageSelector?: boolean
    language?: string
    themeSelector?: boolean
    theme?: string
    editorOption?: Object
    modelValue: string
  }>(),
  {
    width: '100%',
    height: '100%',
    languageSelector: true,
    language: 'python',
    themeSelector: true,
    theme: 'vs',
    editorOption: () => ({}),
    modelValue: ''
  }
)

const emits = defineEmits<{
  (e: 'blur'): void
  (e: 'update:modelValue', val: string): void
}>()

const initWebSocketAndStartClient = (url: string): WebSocket => {
    const webSocket = new WebSocket(url);
    webSocket.onopen = () => {
        const socket = toSocket(webSocket);
        const reader = new WebSocketMessageReader(socket);
        const writer = new WebSocketMessageWriter(socket);
        const languageClient = createLanguageClient({
            reader,
            writer
        });
        languageClient.start();
        reader.onClose(() => languageClient.stop());
    };
    return webSocket;
};


const createLanguageClient = (transports: MessageTransports): MonacoLanguageClient => {
    return new MonacoLanguageClient({
        name: 'Python Language Client',
        clientOptions: {
            // use a language id as a document selector
            documentSelector: ['python'],
            // disable the default error handler
            errorHandler: {
                error: () => ({ action: ErrorAction.Continue }),
                closed: () => ({ action: CloseAction.DoNotRestart })
            }
        },
        // create a language client connection from the JSON RPC connection on demand
        connectionProvider: {
            get: () => {
                return Promise.resolve(transports);
            }
        }
    });
};


const {
  monacoEditorRef,
  createEditor,
  updateVal,
  updateOptions,
  getEditor,
  changeLanguage,
  changeTheme
} = useMonacoEditor(props.language)

onMounted(() => {
  setTimeout(() => {
    const monacoEditor = createEditor(props.editorOption)
    updateMonacoVal(props.modelValue)
    monacoEditor?.onDidChangeModelContent(() => {
      emits('update:modelValue', monacoEditor!.getValue())
    })
    monacoEditor?.onDidBlurEditorText(() => {
      emits('blur')
    })

    initWebSocketAndStartClient('ws://localhost:30001/pyright?authorization=UserAuth');
  }, 3000)
})

watch(
  () => props.modelValue,
  () => {
    updateMonacoVal(props.modelValue)
  }
)

const localLanguage = ref(props.language)

watch(localLanguage, (newLanguage) => {
  changeLanguage(newLanguage)
})

const localTheme = ref(props.theme)
watch(localTheme, (newTheme) => {
  changeTheme(newTheme)
})

function updateMonacoVal(val: string) {
  if (val !== getEditor()?.getValue()) {
    updateVal(val)
  }
}

defineExpose({ updateOptions })
</script>

<template>
  <div class="editor-wrapper">
    <div style="height: 50px;">
      <ElForm :inline="true">
        <ElFormItem v-if="languageSelector" label="language" class="w-30% mb-5px!">
          <ElSelect
            v-model="localLanguage"
            placeholder="Please select language"
            size="small"
            filterable
            style="width: 100px;"
          >
            <ElOption
              v-for="item in languageOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </ElSelect>
        </ElFormItem>
        <ElFormItem v-if="themeSelector" label="theme" class="w-30% mb-5px!">
          <ElSelect v-model="localTheme" placeholder="Please select language" size="small" filterable style="width: 100px;">
            <ElOption
              v-for="item in themeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </ElSelect>
        </ElFormItem>
      </ElForm>
    </div>
    <div style="display: flex;flex-grow: 1;">
      <div ref="monacoEditorRef" class="editor" style="display: block;width: 100%;height: 100%;"></div>
    </div>
  </div>
  
  
</template>

<style scoped>
.editor-wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
}
</style>
